function [varargout] = subsref(hfile, S)
% BVQXfile::subsref  - overloaded method
%
% Usage is either for methods
%
% object.method(arguments)
%
%  - or properties
%
% object.property

% Version:  v0.7g
% Build:    9100821
% Date:     Oct-08 2009, 9:31 PM CEST
% Author:   Jochen Weber, SCAN Unit, Columbia University, NYC, NY, USA
% URL/Info: http://wiki.brainvoyager.com/BVQXtools

% global storage
global bvqxclup;
global bvqxcont;
global bvqxfile_config;

% persistent methods
persistent bvqxfile_methods;
if isempty(bvqxfile_methods)
    bvqxfile_methods = BVQXfile(0, 'methods');
end

% argument check
if nargin < 2 || ...
   ~isstruct(S) || ...
    isempty(S)
    error( ...
        'BVQXfile:BadSubsRef', ...
        'No S struct given or empty.' ...
    );
end

% get structed version
sfile = struct(hfile);

% for multiple objects
nfile = numel(hfile);
if nfile > 1 && ...
    ~strcmp(S(1).type, '()')
    varargout = cell(size(sfile));
    for oc = 1:nfile
        try
            varargout{oc} = subsref(BVQXfile(0, 'makeobject', sfile(oc)), S);
        catch
            error( ...
                'BVQXfile:InternalError', ...
                'Error passing subsref to object %d: %s.', ...
                oc, lasterr ...
            );
        end
    end
    return;
end

% unwind stack
if bvqxfile_config.unwindstack
    BVQXfile(0, 'unwindstack');
end

% default varargout
varargout = cell(1, nargout);
if nargout < 1
    varargout = {};
end

% what type of subsref
slen  = length(S);
stype = S(1).type;
ssubs = S(1).subs;
switch (stype)

    % struct notation
    case {'.'}

        % find lookup
        ifile = find(bvqxclup == sfile.L);

        % already cleared...
        if isempty(ifile)
            error( ...
                'BVQXfile:InvalidObject', ...
                'Object removed from memory.' ...
            );
        end

        % check for subscript type
        if ~ischar(ssubs) || ...
            isempty(ssubs)
            error( ...
                'BVQXfile:BadSubsRef', ...
                'Struct notation needs a non-empty char property.' ...
            );
        end

        % only works for singular object
        if length(hfile) ~= 1
            error( ...
                'BVQXfile:InvalidInputSize', ...
                'Struct notation works only on singular objects.' ...
            );
        end

        % make content linear
        ssubs = ssubs(:)';

        % try different things
        try

            % get file type for methods
            ftype = lower(bvqxcont(ifile).S.Extensions{1});

            % methods
            if isfield(bvqxfile_methods, ftype) && ...
                isfield(bvqxfile_methods.(ftype), lower(ssubs))
                if slen > 1 && ...
                    strcmp(S(2).type, '()')
                    fargs = S(2).subs;
                    S(2)  = [];
                    slen  = length(S);
                else
                    fargs = {};
                end
                try
                    if slen > 1
                        eval(['[varargout{1}]=' ...
                              bvqxfile_methods.(ftype).(lower(ssubs)){1} ...
                            '(hfile, fargs{:});']);
                    else
                        if nargout > 0
                            eval(['[varargout{1:nargout}]=' ...
                                  bvqxfile_methods.(ftype).(lower(ssubs)){1} ...
                                '(hfile, fargs{:});']);
                        else
                            eval(['varargout{1}=' ...
                                  bvqxfile_methods.(ftype).(lower(ssubs)){1} ...
                                '(hfile, fargs{:});']);
                        end
                    end
                catch
                    rethrow(lasterror);
                end

                % if no more args in S
                if slen < 2
                    return;
                end
            elseif isfield(bvqxfile_methods.aft, lower(ssubs))
                if slen > 1 && ...
                    strcmp(S(2).type, '()')
                    fargs = S(2).subs;
                    S(2)  = [];
                    slen  = length(S);
                else
                    fargs = {};
                end
                try
                    if slen > 1
                        eval(['varargout{1}=' ...
                              bvqxfile_methods.aft.(lower(ssubs)){1} ...
                              '(hfile, fargs{:});']);
                    else
                        if nargout > 1
                            eval(['[varargout{1:nargout}]=' ...
                                  bvqxfile_methods.aft.(lower(ssubs)){1} ...
                                  '(hfile, fargs{:});']);
                        else
                            eval(['varargout{1}=' ...
                                  bvqxfile_methods.aft.(lower(ssubs)){1} ...
                                  '(hfile, fargs{:});']);
                        end
                    end
                catch
                    rethrow(lasterror);
                end

                % if no more args in S and non empty input name
                if slen < 2
                    return;
                end
            else
                try
                    varargout{1} = bvqxcont(ifile).C.(ssubs);
                catch
                    rethrow(lasterror);
                end
            end
        catch
            rethrow(lasterror);
        end

        % more sub-indexing ?
        if slen > 1
            try

                % make sure that multiple arguments are OK
                if slen > 2 && ...
                    strcmp(S(end-1).type, '()') && ...
                    strcmp(S(end).type, '.')
                    if nargout > 0
                        [varargout{1:nargout}] = subsref(varargout{1}, S(2:end));
                    else
                        varargout{1} = subsref(varargout{1}, S(2:end));
                    end
                else
                    varargout{1} = subsref(varargout{1}, S(2:end));
                end
            catch
                error( ...
                    'BVQXfile:IllegalSubsRef', ...
                    'Couldn''t pass further subscripting to property value.' ...
                );
            end
        end

    case {'()'}

        % we need non-empty cell subscript
        if ~iscell(ssubs) || ...
            isempty(ssubs)
            error( ...
                'BVQXfile:BadSubsRef', ...
                'Can''t index into BVQXfile matrix.' ...
            );
        end

        % try to retrieve subscripted matrix
        try
            subset = subsref(sfile, S(1));
            hfile  = BVQXfile(0, 'makeobject', subset);
        catch
            error( ...
                'BVQXfile:BadSubsRef', ...
                'Invalid subscript error (%s).', ...
                lasterr ...
            );
        end

        % return sub-matrix if only one subscript
        if slen == 1
            if nargout > 0
                varargout{1} = hfile;
            end
            return;
        end

        % try to pass subscripts
        try
            varargout = cell(size(hfile));
            for oc = 1:numel(hfile)
                varargout{oc} = subsref(hfile(oc), S(2:end));
            end
        catch
            rethrow(lasterror);
        end
    otherwise
        error( ...
            'BVQXfile:BadSubsRef', ...
            'Only struct and array index subsref allowed.' ...
        );
end
